package sample.service.config.custominitializerconfig;

import io.spring.initializr.metadata.InitializrMetadata;
import io.spring.initializr.metadata.InitializrMetadataBuilder;
import io.spring.initializr.metadata.InitializrMetadataProvider;
import io.spring.initializr.metadata.InitializrProperties;
import io.spring.initializr.web.support.DefaultInitializrMetadataProvider;
import io.spring.initializr.web.support.InitializrMetadataUpdateStrategy;
import lombok.Data;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 通过配置文件自定义依赖，并不是总能满足我们的需求，有时候我们还需要自定义一些代码片段，这个时候就需要使用 Spring Initializr  提供的一些扩展钩子：
 * <p>
 * BuildCustomizer：定义Maven/Gradle构建过程，如增加maven build插件
 * ProjectContributor：定义一些个性化的项目目录或者文件
 * MainSourceCodeCustomizer, MainCompilationUnitCustomizer, MainApplicationTypeCustomizer,  TestSourceCodeCustomizer,  TestApplicationTypeCustomizer：项目的源码生成或修改，而不局限于项目语言
 * GitIgnoreCustomizer：定义gitignore文件
 * HelpDocumentCustomizer：定义 HELP.md文件
 * ProjectDescriptionCustomizer：通常用于适应项目描述，例如自动解决框架版本和语言级别的无效组合。
 * <p>
 */
@Configuration
@EnableConfigurationProperties(CustomInitializrProperties.class)
public class CustomInitializrConfiguration {

    /**
     * 最终注入到主容器的初始化属性的承载对象，项目原本有一个默认的初始化属性的注入配置
     * 但其触发注入的条件是 @ConditionalOnMissingBean(InitializrMetadataProvider.class)
     * 即容器中没有InitializrMetadataProvider对象时发生，若我们想要自定义或者说
     * 更改一些必要的默认属性，可用如下的方式主动注入一个
     * 首先：我们可以自定义符合我们自身业务需要的 CustomInitializrProperties 对象
     * 之后，可利用 InitializrMetadataBuilder 建造者去构建整合了我们自定义属性的初始化属性提供者
     * 其中使用的方法为：InitializrMetadataBuilder.fromInitializrProperties 和 withInitializrProperties
     * 后者可根据用户传入参数（true or false）决定是直接替代初始化数据为我们自己的
     * 相关的merge操作如下：
     * public void merge(Env other) {
     *
     *      this.artifactRepository = other.artifactRepository;
     *      this.springBootMetadataUrl = other.springBootMetadataUrl;
     *      this.googleAnalyticsTrackingCode = other.googleAnalyticsTrackingCode;
     *      this.fallbackApplicationName = other.fallbackApplicationName;
     *      this.invalidApplicationNames = other.invalidApplicationNames;
     *      this.forceSsl = other.forceSsl;
     *
     *      this.gradle.merge(other.gradle);
     *      this.kotlin.merge(other.kotlin);
     *      this.maven.merge(other.maven);
     *      this.platform.merge(other.platform);
     *      other.boms.forEach(this.boms::putIfAbsent);
     *      other.repositories.forEach(this.repositories::putIfAbsent);
     * }
     *
     * @param initializrProperties             初始化属性
     * @param customInitializrProperties       自定义的初始化属性
     * @param initializrMetadataUpdateStrategy 初始化属性更新策略对象
     * @return {@link InitializrMetadataProvider} 初始化属性提供者
     */
    @Bean
    public InitializrMetadataProvider customInitializrMetadataProvider(InitializrProperties initializrProperties,
                                                                       CustomInitializrProperties customInitializrProperties,
                                                                       ObjectProvider<InitializrMetadataUpdateStrategy> initializrMetadataUpdateStrategy) {
        InitializrMetadata meta = InitializrMetadataBuilder.fromInitializrProperties(customInitializrProperties.getInitializr())
                .withInitializrProperties(initializrProperties, true).build();
        /* () -> (current) -> current get（）
         *  (current) -> current
         * */
        return new DefaultInitializrMetadataProvider(meta, initializrMetadataUpdateStrategy.getIfAvailable(() -> (current) -> current));
//        return new DefaultInitializrMetadataProvider(meta, initializrMetadataUpdateStrategy.getIfAvailable(() -> {
//            return new InitializrMetadataUpdateStrategy() {
//                @Override
//                public InitializrMetadata update(InitializrMetadata current) {
//                    return current;
//                }
//            };
//        }));
    }


}


@Data
@ConfigurationProperties("custom")
class CustomInitializrProperties {
    @NestedConfigurationProperty
    InitializrProperties initializr = new InitializrProperties();
}